package com.coldlz.mmp.common;

import com.fasterxml.jackson.annotation.JsonInclude;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.core.util.DefaultPrettyPrinter;
import com.fasterxml.jackson.databind.DeserializationFeature;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.ObjectWriter;
import com.fasterxml.jackson.databind.SerializationFeature;
import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule;

import java.text.SimpleDateFormat;
import java.util.Arrays;
import java.util.TimeZone;

public class JacksonUtil {

    private static final String BASE_PACKAGE;
    private static ObjectMapper OBJECT_MAPPER;
    private static ObjectWriter PRETTY_WRITER;
    /**
     * 扫描包的深度，值越小扫描类的范围越大，值越大扫描类的范围越小
     */
    private static final int SCAN_PACKAGE_DEPTH = 3;


    static {
        // 获取当前包的路径
        String[] split = JacksonUtil.class.getName().split("\\.");
        int len = Math.min(split.length, SCAN_PACKAGE_DEPTH);
        String[] newPackage = new String[len];
        System.arraycopy(split, 0, newPackage, 0, len);
        BASE_PACKAGE = String.join(".", Arrays.asList(newPackage));


        ObjectMapper objectMapper = new ObjectMapper();
        JacksonGeneralConfiguration.configure(objectMapper);
        JacksonUtil.OBJECT_MAPPER = objectMapper;
        JacksonUtil.PRETTY_WRITER = OBJECT_MAPPER.writer(new DefaultPrettyPrinter());

    }


    public static <T> T toObject(String jsonStr, TypeReference<T> valueTypeRef) {
        try {
            return OBJECT_MAPPER.readValue(jsonStr, valueTypeRef);
        } catch (JsonProcessingException e) {
            throw new JsonException("json序列化失败：" + jsonStr, e);
        }
    }

    public static <T> T toObject(String jsonStr, Class<T> valueTypeRef) {
        try {
            return OBJECT_MAPPER.readValue(jsonStr, valueTypeRef);
        } catch (JsonProcessingException e) {
            throw new JsonException("json序列化失败：" + jsonStr, e);
        }
    }

    public static String toJsonStr(Object obj) {
        try {
            return OBJECT_MAPPER.writeValueAsString(obj);
        } catch (JsonProcessingException e) {
            throw new JsonException("json序列化失败：class=" + (obj == null ? "null" : obj.getClass()), e);
        }
    }


    public static String toJsonStr(Object obj, boolean prettyPrint) {
        if (prettyPrint) {
            try {
                return PRETTY_WRITER.writeValueAsString(obj);
            } catch (JsonProcessingException e) {
                throw new JsonException("json序列化失败：class=" + (obj == null ? "null" : obj.getClass()), e);
            }
        } else {
            return toJsonStr(obj);
        }
    }

    // ========================下面是序列化和反序列化的实现类=================================================================


    private static class JacksonGeneralConfiguration {

        public static final String DATE_FORMAT = "yyyy-MM-dd HH:mm:ss";

        private static void configure(ObjectMapper objectMapper) {
            objectMapper.setDateFormat(new SimpleDateFormat(DATE_FORMAT));
            objectMapper.setTimeZone(TimeZone.getTimeZone("GMT+8"));

            JavaTimeModule javaTimeModule = new JavaTimeModule();
            objectMapper.registerModule(javaTimeModule);// 注册时间 LocalDateTime 解析器


            // 当序列化一个 Object 或者 无属性对象 时，是否抛出异常
            // false不抛异常，true抛出异常
            objectMapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
            // 如果反序列化时遇到了字符串中多余的属性是否抛出异常
            // false不抛异常，true抛出异常
            objectMapper.configure(SerializationFeature.FAIL_ON_EMPTY_BEANS, false);
            // 是否开启 Date 类型序列化为 时间戳
            objectMapper.configure(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS, false);
            objectMapper.setSerializationInclusion(JsonInclude.Include.ALWAYS);// 总是序列化，即使是null
//            objectMapper.setSerializationInclusion(JsonInclude.Include.NON_NULL);// 非空（非null）的属性才序列化
//            objectMapper.setSerializationInclusion(JsonInclude.Include.NON_EMPTY);// 非空（非null且非空集合）的属性才序列化
        }

    }
}
